<?php
namespace app\common\model;

use app\common\model\users\Users;

/**
 * 用于保存各种统一计算模型
 * Class Calculation
 * @package app\common\model
 */
class Calculation {

    /**
     * 保留小数点默认位数
     */
    const SCALE_DEFAULT_LIST = [
        'default'   => 20,
        'trimZero'  => 30,
    ];

    /**
     * 格式化小数点默认类型
     */
    const DECIMAL_DIGIT_TYPE_LIST = [
        'CURRENCY'  => [30,20], //通用设置，30位，保留 20 小数点
        'LARGE_AMOUNT'  => [40,20], //大额保存，40位，保留 20 小数点
    ];

    // 设置默认的服务费率
    const SERVICE_RATE_DEFAULT = 0.05;

    // 设置节省的默认手续费率
    const FEES_RATE_DEFAULT = [
        'BUY'   => 0.002,
        'SELL'  => 0.002,
    ];


    /**
     * 计算盈利
     * @param array $params 需要参数：['field_price','unit_price','field_quantity','reserved_quantity','field_fees']
     * @param int|null $scale 计算时规范的小数点位数
     * @param bool  $isDetails 是否返回详情 true 则返回所有参数；否则仅返回盈利
     * @return string|string[]|null
     * @throws \Exception
     */
    static function profit(array $params,int $scale = null,$isDetails = false){
        // 验证字段
        self::validateParams($params,['field_price','unit_price','field_quantity','reserved_quantity','field_fees']);
        $scale = self::getScale(__FUNCTION__,$scale);
        $profit = bcmul(
            bcsub($params['field_price'],$params['unit_price'],$scale),
            bcadd($params['field_quantity'],$params['reserved_quantity'],$scale),
            $scale
        );
        $profit = self::trimZero(bcsub($profit,$params['field_fees'],$scale),$scale);
        if($isDetails) {
            $details = [
                'sell'  => self::trimZero(bcmul($params['field_quantity'],$params['unit_price'],$scale)),
                'reserved'  => self::trimZero(bcmul($params['reserved_quantity'],$params['unit_price'],$scale)),
                'field_fees' => self::trimZero($params['field_fees']),
                'profit'    => $profit,
            ];
            $details['cost'] = bcadd($details['sell'],$details['reserved'],$scale);
            return $details;
        } else {
            //仅返回盈利
            return $profit;
        }
    }

    /**
     * 获取省去的第三方手续费
     * @param array $params [unit_price、reserved_quantity]
     * @param int $userId   用户ID
     * @param int|null $scale
     * @return string
     * @throws \Exception
     */
    static function reduceFees(array $params,int $userId,int $scale = null) {
        // 验证字段
        self::validateParams($params,['unit_price','reserved_quantity']);
        $scale = self::getScale(__FUNCTION__,$scale);
        $reserved = bcmul($params['reserved_quantity'],$params['unit_price'],$scale);
        $rate = bcadd(self::FEES_RATE_DEFAULT['BUY'],self::FEES_RATE_DEFAULT['SELL'],$scale);
        return self::trimZero(bcmul($reserved,$rate,$scale));
    }

    /**
     * 将数值格式化
     * @param $decimal
     * @param string $digitType
     */
    static function decimal($decimal,string $digitType = 'CURRENCY') {
        if(is_string($digitType)) {
            $digitType = self::DECIMAL_DIGIT_TYPE_LIST[$digitType];
        }
        $decimal = bcadd($decimal,0,$digitType[1]);
        $len = strlen($decimal);
        if($len < $digitType[0]) {
            $decimal = sprintf('%0' . ($digitType[0] - $len) . 'd',0) . $decimal;
        }
        return $decimal;
    }


    /**
     * 根据不同用户计算不同手续费
     * @param $params 需要参数 ['profit']
     * @param int|null $userId 用户ID
     * @param int|null $scale
     * @return string|string[]|null
     * @throws \Exception
     */
    static function serviceCharge($params,int $userId = null,int $scale = null) {
        // 验证字段
        self::validateParams($params,['profit']);
        // 获取小数点位数
        $scale = self::getScale(__FUNCTION__,$scale);
        if(bccomp($params['profit'],0,$scale) !=1) {    // 如盈利 不大于 0 则返回手续费为 0
            return 0;
        }
        // 获取服务费率
        $serviceRate = self::getServiceRate($userId);
        $serverChargeTmp = bcmul($params['profit'],$serviceRate,$scale + 5);
        $serverCharge = bcadd(0,$serverChargeTmp,$scale);
        if(bccomp($serverChargeTmp,$serverCharge,$scale + 5) == 1) {
            $serverCharge = bcadd($serverCharge,sprintf('0.%0' . $scale . 'd',1),$scale);
        }
        // 返回需要收的服务费
        return self::trimZero($serverCharge,$scale);
    }

    /**
     * 价格去 0 计算
     * @param $price    价格
     * @param int $scale    保留的小数点
     * @return string|string[]|null
     */
    static function trimZero($price,int $scale = null) {
        $scale = self::getScale(__FUNCTION__,$scale);
        return preg_replace_callback('/(\.)?[0]+$/',function(){
            return '';},bcadd($price,0,$scale));
    }


    /**
     * 自定义时间转换函数（strtotime）
     * @param $time
     * @param string $now
     */
    static function strtotimeCustom($time, $now = null) {
        $pattern = "/(\-|\+)? *(\d+) +month(s)?/i";
        $matches = [];
        if(is_string($time) && preg_match($pattern,$time,$matches)) {
            $time = trim(strtr($time,[$matches[0]=>'']));
            list($y,$m,$d,$his) = explode('-',call_user_func_array('date',array_merge(['Y-m-d-H:i:s'],is_integer($now)?[$now]:[])));
            if($matches[1] == '-') {    //减少月份
                $m -= $matches[2];
                if($m < 0) {
                    $m = abs($m);
                    $y -= intval($m/12) + 1;
                    $m = 12 - $m%12;
                } if($m == 0) {
                    $y -= 1;
                    $m = 12;
                }
            } else {    //增加月份
                $m += $matches[2] - 1;
                $y += intval($m/12);
                $m = $m % 12 + 1;
            }
            $days = date('t',strtotime(sprintf('%d-%02d-01 00:00:00',$y,$m)));
            $d = $d > $days?$days:$d;
            $now = strtotime(sprintf('%d-%02d-%02d %s',$y,$m,$d,$his));
            if(empty($time))
                return $now;
        }
        $param = [$time];
        if(is_integer($now))
            $param[] = $now;
        return call_user_func_array('strtotime',$param);
    }


    /**
     * 获取指定时区的 date 格式化
     * @param $format 格式化格式
     * @param null $timeStamp 时间戳
     * @param null $timezone 指定时区
     * @return false|string
     */
    static function date($format,$timeStamp = null,$timezone = null) {
        // 获取时间
        $getDateFunc = function () use($format,$timeStamp){
            return date($format,is_null($timeStamp) || $timeStamp === ''?time():$timeStamp);
        };
        if(empty($timezone)) {  // 不需设置时区，直接返回
            return $getDateFunc();
        }
        // 输出指定时区的时间，然后设置回原来时区
        $defaultTimezone = date_default_timezone_get();
        date_default_timezone_set(self::getTimezone($timezone));
        $result = $getDateFunc();
        date_default_timezone_set($defaultTimezone);
        return $result;
    }


















    /**
     * 获取默认的保留小数点位数
     * @param string $method 请求的方法
     * @param int $scale 小数点位数
     * @return int
     */
    static function getScale(string $method,int $scale = null) {
        if(is_integer($scale)) {
            return $scale;
        }
        return array_key_exists($method,self::SCALE_DEFAULT_LIST)?self::SCALE_DEFAULT_LIST[$method]:self::SCALE_DEFAULT_LIST['default'];
    }

    /**
     * 判断参数
     * @param array $params 请求的参数
     * @param $fields
     * @return bool
     * @throws \Exception
     */
    private static function validateParams(array $params,$fields) {
        foreach($fields as $field) {
            if(!array_key_exists($field,$params)) {
                throw new \Exception('Missing parameter ' . $field);
            }
        }
        return true;
    }

    /**
     * 获取服务费率 【根据不同用户获取不同服务费】
     * @param int|null $userId 用户ID
     * @return float
     */
    private static function getServiceRate(int $userId = null) {
        static $rateList = [];
        if(!array_key_exists($userId,$rateList)) {
            if($details = (new Users())->field(['service_charge_rate'])->find($userId)) {
                $rateList[$userId] = self::trimZero($details->getData()['service_charge_rate']);
            } else {
                $rateList[$userId] = self::SERVICE_RATE_DEFAULT;
            }
        }
        return $rateList[$userId];
    }


    /**
     * 通过时区或时间中的T获取对应值
     * @param string $timezoneOrDateT
     * @param string $type 需要获取的格式：timezone 为 时区；short 为时区简称
     * @return string
     */
    static function getTimezone(string $timezoneOrShort,$type = 'timezone') {
        static $list = null;
        if(is_null($list)) {
            $list = [
                'timezoneToSort'   => [],
                'sortToTimezone'   => [],
            ];
            $timezoneList = 'a:426:{s:14:"Africa/Abidjan";s:3:"GMT";s:12:"Africa/Accra";s:3:"GMT";s:18:"Africa/Addis_Ababa";s:3:"EAT";s:14:"Africa/Algiers";s:3:"CET";s:13:"Africa/Asmara";s:3:"EAT";s:13:"Africa/Bamako";s:3:"GMT";s:13:"Africa/Bangui";s:3:"WAT";s:13:"Africa/Banjul";s:3:"GMT";s:13:"Africa/Bissau";s:3:"GMT";s:15:"Africa/Blantyre";s:3:"CAT";s:18:"Africa/Brazzaville";s:3:"WAT";s:16:"Africa/Bujumbura";s:3:"CAT";s:12:"Africa/Cairo";s:3:"EET";s:17:"Africa/Casablanca";s:3:"+01";s:12:"Africa/Ceuta";s:4:"CEST";s:14:"Africa/Conakry";s:3:"GMT";s:12:"Africa/Dakar";s:3:"GMT";s:20:"Africa/Dar_es_Salaam";s:3:"EAT";s:15:"Africa/Djibouti";s:3:"EAT";s:13:"Africa/Douala";s:3:"WAT";s:15:"Africa/El_Aaiun";s:3:"+01";s:15:"Africa/Freetown";s:3:"GMT";s:15:"Africa/Gaborone";s:3:"CAT";s:13:"Africa/Harare";s:3:"CAT";s:19:"Africa/Johannesburg";s:4:"SAST";s:11:"Africa/Juba";s:3:"EAT";s:14:"Africa/Kampala";s:3:"EAT";s:15:"Africa/Khartoum";s:3:"CAT";s:13:"Africa/Kigali";s:3:"CAT";s:15:"Africa/Kinshasa";s:3:"WAT";s:12:"Africa/Lagos";s:3:"WAT";s:17:"Africa/Libreville";s:3:"WAT";s:11:"Africa/Lome";s:3:"GMT";s:13:"Africa/Luanda";s:3:"WAT";s:17:"Africa/Lubumbashi";s:3:"CAT";s:13:"Africa/Lusaka";s:3:"CAT";s:13:"Africa/Malabo";s:3:"WAT";s:13:"Africa/Maputo";s:3:"CAT";s:13:"Africa/Maseru";s:4:"SAST";s:14:"Africa/Mbabane";s:4:"SAST";s:16:"Africa/Mogadishu";s:3:"EAT";s:15:"Africa/Monrovia";s:3:"GMT";s:14:"Africa/Nairobi";s:3:"EAT";s:15:"Africa/Ndjamena";s:3:"WAT";s:13:"Africa/Niamey";s:3:"WAT";s:17:"Africa/Nouakchott";s:3:"GMT";s:18:"Africa/Ouagadougou";s:3:"GMT";s:17:"Africa/Porto-Novo";s:3:"WAT";s:15:"Africa/Sao_Tome";s:3:"GMT";s:14:"Africa/Tripoli";s:3:"EET";s:12:"Africa/Tunis";s:3:"CET";s:15:"Africa/Windhoek";s:3:"CAT";s:12:"America/Adak";s:3:"HDT";s:17:"America/Anchorage";s:4:"AKDT";s:16:"America/Anguilla";s:3:"AST";s:15:"America/Antigua";s:3:"AST";s:17:"America/Araguaina";s:3:"-03";s:30:"America/Argentina/Buenos_Aires";s:3:"-03";s:27:"America/Argentina/Catamarca";s:3:"-03";s:25:"America/Argentina/Cordoba";s:3:"-03";s:23:"America/Argentina/Jujuy";s:3:"-03";s:26:"America/Argentina/La_Rioja";s:3:"-03";s:25:"America/Argentina/Mendoza";s:3:"-03";s:30:"America/Argentina/Rio_Gallegos";s:3:"-03";s:23:"America/Argentina/Salta";s:3:"-03";s:26:"America/Argentina/San_Juan";s:3:"-03";s:26:"America/Argentina/San_Luis";s:3:"-03";s:25:"America/Argentina/Tucuman";s:3:"-03";s:25:"America/Argentina/Ushuaia";s:3:"-03";s:13:"America/Aruba";s:3:"AST";s:16:"America/Asuncion";s:3:"-04";s:16:"America/Atikokan";s:3:"EST";s:13:"America/Bahia";s:3:"-03";s:22:"America/Bahia_Banderas";s:3:"CDT";s:16:"America/Barbados";s:3:"AST";s:13:"America/Belem";s:3:"-03";s:14:"America/Belize";s:3:"CST";s:20:"America/Blanc-Sablon";s:3:"AST";s:17:"America/Boa_Vista";s:3:"-04";s:14:"America/Bogota";s:3:"-05";s:13:"America/Boise";s:3:"MDT";s:21:"America/Cambridge_Bay";s:3:"MDT";s:20:"America/Campo_Grande";s:3:"-04";s:14:"America/Cancun";s:3:"EST";s:15:"America/Caracas";s:3:"-04";s:15:"America/Cayenne";s:3:"-03";s:14:"America/Cayman";s:3:"EST";s:15:"America/Chicago";s:3:"CDT";s:17:"America/Chihuahua";s:3:"MDT";s:18:"America/Costa_Rica";s:3:"CST";s:15:"America/Creston";s:3:"MST";s:14:"America/Cuiaba";s:3:"-04";s:15:"America/Curacao";s:3:"AST";s:20:"America/Danmarkshavn";s:3:"GMT";s:14:"America/Dawson";s:3:"PDT";s:20:"America/Dawson_Creek";s:3:"MST";s:14:"America/Denver";s:3:"MDT";s:15:"America/Detroit";s:3:"EDT";s:16:"America/Dominica";s:3:"AST";s:16:"America/Edmonton";s:3:"MDT";s:16:"America/Eirunepe";s:3:"-05";s:19:"America/El_Salvador";s:3:"CST";s:19:"America/Fort_Nelson";s:3:"MST";s:17:"America/Fortaleza";s:3:"-03";s:17:"America/Glace_Bay";s:3:"ADT";s:15:"America/Godthab";s:3:"-02";s:17:"America/Goose_Bay";s:3:"ADT";s:18:"America/Grand_Turk";s:3:"EDT";s:15:"America/Grenada";s:3:"AST";s:18:"America/Guadeloupe";s:3:"AST";s:17:"America/Guatemala";s:3:"CST";s:17:"America/Guayaquil";s:3:"-05";s:14:"America/Guyana";s:3:"-04";s:15:"America/Halifax";s:3:"ADT";s:14:"America/Havana";s:3:"CDT";s:18:"America/Hermosillo";s:3:"MST";s:28:"America/Indiana/Indianapolis";s:3:"EDT";s:20:"America/Indiana/Knox";s:3:"CDT";s:23:"America/Indiana/Marengo";s:3:"EDT";s:26:"America/Indiana/Petersburg";s:3:"EDT";s:25:"America/Indiana/Tell_City";s:3:"CDT";s:21:"America/Indiana/Vevay";s:3:"EDT";s:25:"America/Indiana/Vincennes";s:3:"EDT";s:23:"America/Indiana/Winamac";s:3:"EDT";s:14:"America/Inuvik";s:3:"MDT";s:15:"America/Iqaluit";s:3:"EDT";s:15:"America/Jamaica";s:3:"EST";s:14:"America/Juneau";s:4:"AKDT";s:27:"America/Kentucky/Louisville";s:3:"EDT";s:27:"America/Kentucky/Monticello";s:3:"EDT";s:18:"America/Kralendijk";s:3:"AST";s:14:"America/La_Paz";s:3:"-04";s:12:"America/Lima";s:3:"-05";s:19:"America/Los_Angeles";s:3:"PDT";s:21:"America/Lower_Princes";s:3:"AST";s:14:"America/Maceio";s:3:"-03";s:15:"America/Managua";s:3:"CST";s:14:"America/Manaus";s:3:"-04";s:15:"America/Marigot";s:3:"AST";s:18:"America/Martinique";s:3:"AST";s:17:"America/Matamoros";s:3:"CDT";s:16:"America/Mazatlan";s:3:"MDT";s:17:"America/Menominee";s:3:"CDT";s:14:"America/Merida";s:3:"CDT";s:18:"America/Metlakatla";s:4:"AKDT";s:19:"America/Mexico_City";s:3:"CDT";s:16:"America/Miquelon";s:3:"-02";s:15:"America/Moncton";s:3:"ADT";s:17:"America/Monterrey";s:3:"CDT";s:18:"America/Montevideo";s:3:"-03";s:18:"America/Montserrat";s:3:"AST";s:14:"America/Nassau";s:3:"EDT";s:16:"America/New_York";s:3:"EDT";s:15:"America/Nipigon";s:3:"EDT";s:12:"America/Nome";s:4:"AKDT";s:15:"America/Noronha";s:3:"-02";s:27:"America/North_Dakota/Beulah";s:3:"CDT";s:27:"America/North_Dakota/Center";s:3:"CDT";s:30:"America/North_Dakota/New_Salem";s:3:"CDT";s:15:"America/Ojinaga";s:3:"MDT";s:14:"America/Panama";s:3:"EST";s:19:"America/Pangnirtung";s:3:"EDT";s:18:"America/Paramaribo";s:3:"-03";s:15:"America/Phoenix";s:3:"MST";s:22:"America/Port-au-Prince";s:3:"EDT";s:21:"America/Port_of_Spain";s:3:"AST";s:19:"America/Porto_Velho";s:3:"-04";s:19:"America/Puerto_Rico";s:3:"AST";s:20:"America/Punta_Arenas";s:3:"-03";s:19:"America/Rainy_River";s:3:"CDT";s:20:"America/Rankin_Inlet";s:3:"CDT";s:14:"America/Recife";s:3:"-03";s:14:"America/Regina";s:3:"CST";s:16:"America/Resolute";s:3:"CDT";s:18:"America/Rio_Branco";s:3:"-05";s:16:"America/Santarem";s:3:"-03";s:16:"America/Santiago";s:3:"-04";s:21:"America/Santo_Domingo";s:3:"AST";s:17:"America/Sao_Paulo";s:3:"-03";s:20:"America/Scoresbysund";s:3:"+00";s:13:"America/Sitka";s:4:"AKDT";s:21:"America/St_Barthelemy";s:3:"AST";s:16:"America/St_Johns";s:3:"NDT";s:16:"America/St_Kitts";s:3:"AST";s:16:"America/St_Lucia";s:3:"AST";s:17:"America/St_Thomas";s:3:"AST";s:18:"America/St_Vincent";s:3:"AST";s:21:"America/Swift_Current";s:3:"CST";s:19:"America/Tegucigalpa";s:3:"CST";s:13:"America/Thule";s:3:"ADT";s:19:"America/Thunder_Bay";s:3:"EDT";s:15:"America/Tijuana";s:3:"PDT";s:15:"America/Toronto";s:3:"EDT";s:15:"America/Tortola";s:3:"AST";s:17:"America/Vancouver";s:3:"PDT";s:18:"America/Whitehorse";s:3:"PDT";s:16:"America/Winnipeg";s:3:"CDT";s:15:"America/Yakutat";s:4:"AKDT";s:19:"America/Yellowknife";s:3:"MDT";s:16:"Antarctica/Casey";s:3:"+08";s:16:"Antarctica/Davis";s:3:"+07";s:25:"Antarctica/DumontDUrville";s:3:"+10";s:20:"Antarctica/Macquarie";s:3:"+11";s:17:"Antarctica/Mawson";s:3:"+05";s:18:"Antarctica/McMurdo";s:4:"NZST";s:17:"Antarctica/Palmer";s:3:"-03";s:18:"Antarctica/Rothera";s:3:"-03";s:16:"Antarctica/Syowa";s:3:"+03";s:16:"Antarctica/Troll";s:3:"+02";s:17:"Antarctica/Vostok";s:3:"+06";s:19:"Arctic/Longyearbyen";s:4:"CEST";s:9:"Asia/Aden";s:3:"+03";s:11:"Asia/Almaty";s:3:"+06";s:10:"Asia/Amman";s:4:"EEST";s:11:"Asia/Anadyr";s:3:"+12";s:10:"Asia/Aqtau";s:3:"+05";s:11:"Asia/Aqtobe";s:3:"+05";s:13:"Asia/Ashgabat";s:3:"+05";s:11:"Asia/Atyrau";s:3:"+05";s:12:"Asia/Baghdad";s:3:"+03";s:12:"Asia/Bahrain";s:3:"+03";s:9:"Asia/Baku";s:3:"+04";s:12:"Asia/Bangkok";s:3:"+07";s:12:"Asia/Barnaul";s:3:"+07";s:11:"Asia/Beirut";s:4:"EEST";s:12:"Asia/Bishkek";s:3:"+06";s:11:"Asia/Brunei";s:3:"+08";s:10:"Asia/Chita";s:3:"+09";s:15:"Asia/Choibalsan";s:3:"+08";s:12:"Asia/Colombo";s:5:"+0530";s:13:"Asia/Damascus";s:4:"EEST";s:10:"Asia/Dhaka";s:3:"+06";s:9:"Asia/Dili";s:3:"+09";s:10:"Asia/Dubai";s:3:"+04";s:13:"Asia/Dushanbe";s:3:"+05";s:14:"Asia/Famagusta";s:4:"EEST";s:9:"Asia/Gaza";s:4:"EEST";s:11:"Asia/Hebron";s:4:"EEST";s:16:"Asia/Ho_Chi_Minh";s:3:"+07";s:14:"Asia/Hong_Kong";s:3:"HKT";s:9:"Asia/Hovd";s:3:"+07";s:12:"Asia/Irkutsk";s:3:"+08";s:12:"Asia/Jakarta";s:3:"WIB";s:13:"Asia/Jayapura";s:3:"WIT";s:14:"Asia/Jerusalem";s:3:"IDT";s:10:"Asia/Kabul";s:5:"+0430";s:14:"Asia/Kamchatka";s:3:"+12";s:12:"Asia/Karachi";s:3:"PKT";s:14:"Asia/Kathmandu";s:5:"+0545";s:13:"Asia/Khandyga";s:3:"+09";s:12:"Asia/Kolkata";s:3:"IST";s:16:"Asia/Krasnoyarsk";s:3:"+07";s:17:"Asia/Kuala_Lumpur";s:3:"+08";s:12:"Asia/Kuching";s:3:"+08";s:11:"Asia/Kuwait";s:3:"+03";s:10:"Asia/Macau";s:3:"CST";s:12:"Asia/Magadan";s:3:"+11";s:13:"Asia/Makassar";s:4:"WITA";s:11:"Asia/Manila";s:3:"PST";s:11:"Asia/Muscat";s:3:"+04";s:12:"Asia/Nicosia";s:4:"EEST";s:17:"Asia/Novokuznetsk";s:3:"+07";s:16:"Asia/Novosibirsk";s:3:"+07";s:9:"Asia/Omsk";s:3:"+06";s:9:"Asia/Oral";s:3:"+05";s:15:"Asia/Phnom_Penh";s:3:"+07";s:14:"Asia/Pontianak";s:3:"WIB";s:14:"Asia/Pyongyang";s:3:"KST";s:10:"Asia/Qatar";s:3:"+03";s:13:"Asia/Qostanay";s:3:"+06";s:14:"Asia/Qyzylorda";s:3:"+05";s:11:"Asia/Riyadh";s:3:"+03";s:13:"Asia/Sakhalin";s:3:"+11";s:14:"Asia/Samarkand";s:3:"+05";s:10:"Asia/Seoul";s:3:"KST";s:13:"Asia/Shanghai";s:3:"CST";s:14:"Asia/Singapore";s:3:"+08";s:18:"Asia/Srednekolymsk";s:3:"+11";s:11:"Asia/Taipei";s:3:"CST";s:13:"Asia/Tashkent";s:3:"+05";s:12:"Asia/Tbilisi";s:3:"+04";s:11:"Asia/Tehran";s:5:"+0430";s:12:"Asia/Thimphu";s:3:"+06";s:10:"Asia/Tokyo";s:3:"JST";s:10:"Asia/Tomsk";s:3:"+07";s:16:"Asia/Ulaanbaatar";s:3:"+08";s:11:"Asia/Urumqi";s:3:"+06";s:13:"Asia/Ust-Nera";s:3:"+10";s:14:"Asia/Vientiane";s:3:"+07";s:16:"Asia/Vladivostok";s:3:"+10";s:12:"Asia/Yakutsk";s:3:"+09";s:11:"Asia/Yangon";s:5:"+0630";s:18:"Asia/Yekaterinburg";s:3:"+05";s:12:"Asia/Yerevan";s:3:"+04";s:15:"Atlantic/Azores";s:3:"+00";s:16:"Atlantic/Bermuda";s:3:"ADT";s:15:"Atlantic/Canary";s:4:"WEST";s:19:"Atlantic/Cape_Verde";s:3:"-01";s:14:"Atlantic/Faroe";s:4:"WEST";s:16:"Atlantic/Madeira";s:4:"WEST";s:18:"Atlantic/Reykjavik";s:3:"GMT";s:22:"Atlantic/South_Georgia";s:3:"-02";s:18:"Atlantic/St_Helena";s:3:"GMT";s:16:"Atlantic/Stanley";s:3:"-03";s:18:"Australia/Adelaide";s:4:"ACST";s:18:"Australia/Brisbane";s:4:"AEST";s:21:"Australia/Broken_Hill";s:4:"ACST";s:16:"Australia/Currie";s:4:"AEST";s:16:"Australia/Darwin";s:4:"ACST";s:15:"Australia/Eucla";s:5:"+0845";s:16:"Australia/Hobart";s:4:"AEST";s:18:"Australia/Lindeman";s:4:"AEST";s:19:"Australia/Lord_Howe";s:5:"+1030";s:19:"Australia/Melbourne";s:4:"AEST";s:15:"Australia/Perth";s:4:"AWST";s:16:"Australia/Sydney";s:4:"AEST";s:16:"Europe/Amsterdam";s:4:"CEST";s:14:"Europe/Andorra";s:4:"CEST";s:16:"Europe/Astrakhan";s:3:"+04";s:13:"Europe/Athens";s:4:"EEST";s:15:"Europe/Belgrade";s:4:"CEST";s:13:"Europe/Berlin";s:4:"CEST";s:17:"Europe/Bratislava";s:4:"CEST";s:15:"Europe/Brussels";s:4:"CEST";s:16:"Europe/Bucharest";s:4:"EEST";s:15:"Europe/Budapest";s:4:"CEST";s:15:"Europe/Busingen";s:4:"CEST";s:15:"Europe/Chisinau";s:4:"EEST";s:17:"Europe/Copenhagen";s:4:"CEST";s:13:"Europe/Dublin";s:3:"IST";s:16:"Europe/Gibraltar";s:4:"CEST";s:15:"Europe/Guernsey";s:3:"BST";s:15:"Europe/Helsinki";s:4:"EEST";s:18:"Europe/Isle_of_Man";s:3:"BST";s:15:"Europe/Istanbul";s:3:"+03";s:13:"Europe/Jersey";s:3:"BST";s:18:"Europe/Kaliningrad";s:3:"EET";s:11:"Europe/Kiev";s:4:"EEST";s:12:"Europe/Kirov";s:3:"+03";s:13:"Europe/Lisbon";s:4:"WEST";s:16:"Europe/Ljubljana";s:4:"CEST";s:13:"Europe/London";s:3:"BST";s:17:"Europe/Luxembourg";s:4:"CEST";s:13:"Europe/Madrid";s:4:"CEST";s:12:"Europe/Malta";s:4:"CEST";s:16:"Europe/Mariehamn";s:4:"EEST";s:12:"Europe/Minsk";s:3:"+03";s:13:"Europe/Monaco";s:4:"CEST";s:13:"Europe/Moscow";s:3:"MSK";s:11:"Europe/Oslo";s:4:"CEST";s:12:"Europe/Paris";s:4:"CEST";s:16:"Europe/Podgorica";s:4:"CEST";s:13:"Europe/Prague";s:4:"CEST";s:11:"Europe/Riga";s:4:"EEST";s:11:"Europe/Rome";s:4:"CEST";s:13:"Europe/Samara";s:3:"+04";s:17:"Europe/San_Marino";s:4:"CEST";s:15:"Europe/Sarajevo";s:4:"CEST";s:14:"Europe/Saratov";s:3:"+04";s:17:"Europe/Simferopol";s:3:"MSK";s:13:"Europe/Skopje";s:4:"CEST";s:12:"Europe/Sofia";s:4:"EEST";s:16:"Europe/Stockholm";s:4:"CEST";s:14:"Europe/Tallinn";s:4:"EEST";s:13:"Europe/Tirane";s:4:"CEST";s:16:"Europe/Ulyanovsk";s:3:"+04";s:15:"Europe/Uzhgorod";s:4:"EEST";s:12:"Europe/Vaduz";s:4:"CEST";s:14:"Europe/Vatican";s:4:"CEST";s:13:"Europe/Vienna";s:4:"CEST";s:14:"Europe/Vilnius";s:4:"EEST";s:16:"Europe/Volgograd";s:3:"+04";s:13:"Europe/Warsaw";s:4:"CEST";s:13:"Europe/Zagreb";s:4:"CEST";s:17:"Europe/Zaporozhye";s:4:"EEST";s:13:"Europe/Zurich";s:4:"CEST";s:19:"Indian/Antananarivo";s:3:"EAT";s:13:"Indian/Chagos";s:3:"+06";s:16:"Indian/Christmas";s:3:"+07";s:12:"Indian/Cocos";s:5:"+0630";s:13:"Indian/Comoro";s:3:"EAT";s:16:"Indian/Kerguelen";s:3:"+05";s:11:"Indian/Mahe";s:3:"+04";s:15:"Indian/Maldives";s:3:"+05";s:16:"Indian/Mauritius";s:3:"+04";s:14:"Indian/Mayotte";s:3:"EAT";s:14:"Indian/Reunion";s:3:"+04";s:12:"Pacific/Apia";s:3:"+13";s:16:"Pacific/Auckland";s:4:"NZST";s:20:"Pacific/Bougainville";s:3:"+11";s:15:"Pacific/Chatham";s:5:"+1245";s:13:"Pacific/Chuuk";s:3:"+10";s:14:"Pacific/Easter";s:3:"-06";s:13:"Pacific/Efate";s:3:"+11";s:17:"Pacific/Enderbury";s:3:"+13";s:15:"Pacific/Fakaofo";s:3:"+13";s:12:"Pacific/Fiji";s:3:"+12";s:16:"Pacific/Funafuti";s:3:"+12";s:17:"Pacific/Galapagos";s:3:"-06";s:15:"Pacific/Gambier";s:3:"-09";s:19:"Pacific/Guadalcanal";s:3:"+11";s:12:"Pacific/Guam";s:4:"ChST";s:16:"Pacific/Honolulu";s:3:"HST";s:18:"Pacific/Kiritimati";s:3:"+14";s:14:"Pacific/Kosrae";s:3:"+11";s:17:"Pacific/Kwajalein";s:3:"+12";s:14:"Pacific/Majuro";s:3:"+12";s:17:"Pacific/Marquesas";s:5:"-0930";s:14:"Pacific/Midway";s:3:"SST";s:13:"Pacific/Nauru";s:3:"+12";s:12:"Pacific/Niue";s:3:"-11";s:15:"Pacific/Norfolk";s:3:"+11";s:14:"Pacific/Noumea";s:3:"+11";s:17:"Pacific/Pago_Pago";s:3:"SST";s:13:"Pacific/Palau";s:3:"+09";s:16:"Pacific/Pitcairn";s:3:"-08";s:15:"Pacific/Pohnpei";s:3:"+11";s:20:"Pacific/Port_Moresby";s:3:"+10";s:17:"Pacific/Rarotonga";s:3:"-10";s:14:"Pacific/Saipan";s:4:"ChST";s:14:"Pacific/Tahiti";s:3:"-10";s:14:"Pacific/Tarawa";s:3:"+12";s:17:"Pacific/Tongatapu";s:3:"+13";s:12:"Pacific/Wake";s:3:"+12";s:14:"Pacific/Wallis";s:3:"+12";s:3:"UTC";s:3:"UTC";}';
            $list['timezoneToSort'] = unserialize($timezoneList);
            foreach($list['timezoneToSort'] as $timezone=>$timeT) {
                if(!array_key_exists($timeT,$list['sortToTimezone'])) {
                    $list['sortToTimezone'][$timeT] = $timezone;
                }
            }
        }
        if(strlen($timezoneOrShort) > 7) {
            // 原来为 timezone
            $timezone = $timezoneOrShort;
            $short = $list['timezoneToSort'][$timezone];
        } else {
            $short = $timezoneOrShort;
            $timezone =  $list['sortToTimezone'][$short];;
        }
        return $type=='timezone'?$timezone:$short;
    }
}